From 483397e9f03ffc05bde6aae19bdc4cf9dbc14cc5 Mon Sep 17 00:00:00 2001 From: robertl Date: Sat, 26 Jul 2008 17:27:14 +0000 Subject: [PATCH] =?utf8?q?Dr.=20J=C3=BCrgen=20Neumann=20contributes=20supp?= =?utf8?q?ort=20for=20Medion=20GoPal.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit git-svn-id: http://gpsbabel.googlecode.com/svn/trunk@3303 f51c46e8-681c-474f-0cfe-069cfd0219fb --- gpsbabel/Makefile.in | 2 +- gpsbabel/gopal.c | 396 ++++++++++++++++++ gpsbabel/testo | 19 + gpsbabel/vecs.c | 7 + gpsbabel/xmldoc/formats/gopal.xml | 39 ++ .../xmldoc/formats/options/gopal-clean.xml | 1 + .../xmldoc/formats/options/gopal-date.xml | 3 + .../xmldoc/formats/options/gopal-maxspeed.xml | 3 + .../xmldoc/formats/options/gopal-minspeed.xml | 3 + 9 files changed, 472 insertions(+), 1 deletion(-) create mode 100644 gpsbabel/gopal.c create mode 100644 gpsbabel/xmldoc/formats/gopal.xml create mode 100644 gpsbabel/xmldoc/formats/options/gopal-clean.xml create mode 100644 gpsbabel/xmldoc/formats/options/gopal-date.xml create mode 100644 gpsbabel/xmldoc/formats/options/gopal-maxspeed.xml create mode 100644 gpsbabel/xmldoc/formats/options/gopal-minspeed.xml diff --git a/gpsbabel/Makefile.in b/gpsbabel/Makefile.in index 8a2c91931..6bf04afdc 100644 --- a/gpsbabel/Makefile.in +++ b/gpsbabel/Makefile.in @@ -59,7 +59,7 @@ ALL_FMTS=$(MINIMAL_FMTS) gtm.o gpsutil.o pcx.o cetus.o copilot.o \ wbt-200.o stmsdf.o gtrnctr.o dmtlog.o raymarine.o alan.o vitovtt.o \ ggv_log.o g7towin.o garmin_gpi.o lmx.o random.o xol.o dg-100.o \ navilink.o mtk_logger.o ik3d.o osm.o destinator.o exif.o vidaone.o \ - igo8.o + igo8.o gopal.o FMTS=@FMTS@ diff --git a/gpsbabel/gopal.c b/gpsbabel/gopal.c new file mode 100644 index 000000000..7f6d0fe56 --- /dev/null +++ b/gpsbabel/gopal.c @@ -0,0 +1,396 @@ +/* + + + Copyright (C) 2008 Dr. Jürgen Neumann, Juergen.Neumann@online.de + Copyright (C) 2005 Robert Lipe, robertlipe@usa.net (based on nmea.c) + Copyright (C) 20XX probably many others from the gpsbabel development team ;-) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + ===================================================================================== + + This file allows gpsbabel to read and write the internal track log format used by + GoPal navigation systems. They produce a simple line-oriented format with one point per + second. Unfortunately the the data does not contain a valid date, only some kind of timetick, + together with each point (perhaps by mistake ??). So we have to parse the filename for a valid starting + date and add the timeoffset. Second problem (at least to me) was that irregularly stupid errors were + in the data, i.e. only one data point shows a totally wrong longitude or latitude. Everything else in + the dataset seems ok, so I needed a way to sort out these errors. My solution is to calculate the speed + between successive points and drop points not between minspeed and maxspeed. This way I can sort out most + of this annoying bugs, a side effect is that if a minimum speed > 0 is set points with the same coodinates are also + dropped. + + Fileformat GoPal + TICK; TIME UTC; LONG; LAT; HEIGHT; SPEED km/h; FIX; HDOP; SAT + 3801444, 080558, 2.944362, 43.262117, 295.28, 0.12964, 2, 2.900000, 3 + Filenames: + trackYYYYMMDD_HHMMSS.trk + A_YYYYMMDD_HHMMSS.trk + with HHMMSS local time (not UTC) + + History + 2008-07-18 initial release of Version 0.1 + 2008-07-26 bugfix: filenamehandling linux, format specification in write statement + + ToDo: + - check for midnight & adjust +*/ + +#include "defs.h" +#include +#include "csv_util.h" +#include +#include "strptime.h" +#include "jeeps/gpsmath.h" +#include "grtcirc.h" +#define MYNAME "gopal" + +static gbfile *fin, *fout; + +static struct tm tm,filenamedate, trackdate; +time_t tx; +char tmp[64]; +char routename[64]; +static char *optdate=NULL; +static char *optmaxspeed=NULL; +static char *optminspeed=NULL; +static char *optclean= NULL; +static double minspeed,maxspeed; +static struct tm opt_tm; /* converted "date" parameter */ +static +arglist_t gopal_args[] = { + {"date", &optdate, "Complete date-free tracks with given date (YYYYMMDD).", NULL, ARGTYPE_INT, ARG_NOMINMAX }, + {"maxspeed", &optmaxspeed, "The maximum speed (km/h) traveling from waypoint to waypoint.", "200", ARGTYPE_INT, "1", "1000" }, + {"minspeed", &optminspeed, "The minimum speed (km/h) traveling from waypoint to waypoint.\nset >0 to remove duplicate waypoints", "0", ARGTYPE_INT, "0", "999" }, + {"clean", &optclean, "Cleanup common errors in trackdata", "1", ARGTYPE_BOOL, ARG_NOMINMAX }, + ARG_TERMINATOR +}; + +#define CHECK_BOOL(a) if (a && (*a == '0')) a = NULL + +int gopal_check_line(char *line) +{ + char *c = line; + int i = 0; + while ((c = strchr(c, ','))) + { + c++; + i++; + } + if (i != 8) + { + snprintf(tmp,sizeof(tmp),"\"%s\"\n",line); + fprintf(stderr,tmp); + } + return i; +} + + + +/******************************************************************************* +* %%% global callbacks called by gpsbabel main process %%% * +*******************************************************************************/ + +static void +gopal_rd_init(const char *fname) +{char buff[32]; + char *ck; + char *filename; + CHECK_BOOL(optclean); + if (optminspeed) + { + minspeed=atof(optminspeed); + if (global_opts.debug_level > 1) fprintf(stderr,"options from command line : gopal minspeed = %s\n",optminspeed); + } + else + minspeed=0; + if (optmaxspeed) + { + maxspeed=atof(optmaxspeed); + if (global_opts.debug_level > 1) fprintf(stderr,"options from command line : gopal maxspeed = %s\n",optmaxspeed); + } + else + maxspeed=200; + if (global_opts.debug_level > 1) fprintf(stderr,"setting minspeed to %5.1lf km/h and maxspeed to %5.1lf km/h\n",minspeed,maxspeed); + + fin = gbfopen(fname, "r", MYNAME); + memset(buff,0,sizeof(buff)); + if (optdate) + { + memset(&opt_tm, 0, sizeof(opt_tm)); + + ck = (char *)strptime(optdate, "%Y%m%d", &opt_tm); + if ((ck == NULL) || (*ck != '\0') || (strlen(optdate) != 8)) + fatal(MYNAME ": Invalid date \"%s\"!\n", optdate); + else if (opt_tm.tm_year < 70) + fatal(MYNAME ": Date \"%s\" is out of range (have to be 19700101 or later)!\n", optdate); + tx = mkgmtime(&opt_tm); + + } + else + { + /* remove path */ + filename = get_filename(fname); + + if ((strncmp(filename,"track",5)==0)&&(strlen(filename)>13)) // we need at least 13 letters: trackYYYYMMDD... + { + strncpy(&buff[0],&filename[5],8); + } + else + if ((strncmp(filename,"A_",2)==0)&&(strlen(filename)>10))// here we expect at least 10 letters: A_YYYYMMDD... + { + strncpy(&buff[0],&filename[2],8); + } + // in buff we should now have something wich looks like a valid date starting with YYYYMMDD + ck = (char *)strptime(buff, "%Y%m%d", &filenamedate); + if (((ck == NULL) || (*ck != '\0') )&&!(optdate)) + fatal(MYNAME ": Invalid date in filename \"%s\", try to set manually using \"optdate\" switch!\n", buff); + else if (filenamedate.tm_year < 70) + fatal(MYNAME ": Date \"%s\" is out of range (have to be 19700101 or later)!\n", buff); + tx= mkgmtime(&filenamedate); + } +} + +static void +gopal_rd_deinit(void) +{ + gbfclose(fin); +} + +static void +gopal_read(void) +{ + + char *buff; + char *str, *c; + int column; + long line; + double hmsd,speed; + int fix, hms; + route_head *route; + waypoint *wpt, *lastwpt=NULL; + double long_old,lat_old; + char tbuffer[64]; + long_old=0;lat_old=0; + strftime(routename,sizeof(routename),"Tracklog %c",localtime(&tx)); + + route = route_head_alloc(); + route->rte_name=xstrdup(routename); + route_add_head(route); + + line=0; + while ((buff = gbfgetstr(fin))) + { + str = buff = lrtrim(buff); + if (*buff == '\0') continue; + if (gopal_check_line(buff)!=8)continue; + wpt = waypt_new(); + + column = -1; + // the format of gopal is quite simple. Unfortunately the developers forgot the date as the first element... + //TICK; TIME; LONG; LAT; HEIGHT; SPEED; Fix; HDOP; SAT + //3801444, 080558, 2.944362, 43.262117, 295.28, 0.12964, 2, 2.900000, 3 + c = csv_lineparse(str, ",", "", column++); + while (c != NULL) + { + switch(column) + { + case 0: /* "-" */ /* unknown fields for the moment */ + //sscanf(c, "%llu", &wpt->microseconds); + break; + case 1: /* Time UTC */ + sscanf(c,"%lf",&hmsd); + hms = (int) hmsd; + tm.tm_sec = hms % 100; + hms = hms / 100; + tm.tm_min = hms % 100; + hms = hms / 100; + tm.tm_hour = hms % 100; + tm.tm_year=trackdate.tm_year; + tm.tm_mon=trackdate.tm_mon; + tm.tm_mday=trackdate.tm_mday; + wpt->creation_time = tx+((((time_t)tm.tm_hour * 60) + tm.tm_min) * 60) + tm.tm_sec; + if (global_opts.debug_level > 1){ + strftime(tbuffer, sizeof(tbuffer), "%c", gmtime(&wpt->creation_time)); + printf("parsed timestamp: %s\n",tbuffer); + } + break; + + case 2: /* longitude */ + sscanf(c, "%lf", &wpt->longitude); + break; + + case 3: /* latitude */ + sscanf(c, "%lf", &wpt->latitude); + break; + case 4: /* altitude */ + sscanf(c, "%lf", &wpt->altitude); + break; + case 5: /* speed */ + //sscanf(c, "%lf", &wpt->speed); + wpt->speed=atof(c); + if (global_opts.debug_level > 1){ + printf("parsed speed: %8.5f\n",wpt->speed); + } + break; + case 6: /* type of fix */ + sscanf(c, "%d", &fix); + //my device shows only 0 or 2 + //should i guess from no of sats if 2d or 3d? + switch (fix) { + case 0: wpt->fix = fix_none;break; + case 2: wpt->fix = fix_2d;break; + //case 3: wpt->fix = fix_3d;break; + //case 4: wpt->fix = fix_dgps;break; /* 2D_diff */ + //case 5: wpt->fix = fix_dgps;break; /* 3D_diff */ + default: + wpt->fix = fix_unknown; + break; + } + break; + case 7: /* hdop */ + wpt->hdop = atof(c); + //sscanf(c, "%lf", &wpt->hdop); does not work ??? + //wpt->vdop=0;wpt->hdop=0; + break; + case 8: /* number of sats */ + sscanf(c, "%d", &wpt->sat); + break; + + } + c = csv_lineparse(NULL, ",", "", column++); + } + line++; + + if ((wpt->fix != fix_none)&&(lat_old==0)){ //first-time init + lat_old=wpt->latitude; + long_old=wpt->longitude; + //route_add_wpt(route, wpt); + lastwpt=wpt; + } + //calculate the speed to reach this waypoint from the last. This way I try to sort out invalid waypoints + speed=0; + if (lastwpt !=NULL) + { + speed=3.6*radtometers(gcdist(RAD(lastwpt->latitude), RAD(lastwpt->longitude), RAD(wpt->latitude), RAD(wpt->longitude))) / abs(wpt->creation_time - lastwpt->creation_time); + //printf("speed line %d %lf \n",line,speed); + } + /* Error handling: in the tracklog of my device sometimes "jump" waypoints ;-) */ + if ((optclean) && + (((wpt->longitude==0.0)|| (wpt->latitude==0.0)||(abs(wpt->latitude)>90)||(abs(wpt->longitude)>180))|| + ((speed>maxspeed)||(speed 1) fprintf(stderr,"Problem in or around line %5lu: \"%s\" %lf km/h\n",line,buff,speed); + } + else + { + if (global_opts.debug_level > 1) fprintf(stderr,"valid line %5lu: \"%s\" %lf km/h\n",line,buff,speed); + lastwpt=wpt; + long_old=wpt->longitude; + lat_old=wpt->latitude; + route_add_wpt(route,wpt); + waypt_add(waypt_dupe( wpt)); + } + } +} + +static void +gopal_route_hdr(const route_head *route) +{ + +} + +static void +gopal_route_tlr(const route_head *rte) +{ +} +static void +gopal_write_waypt(const waypoint *wpt) +{ + char tbuffer[64]; + int fix=fix_unknown; + //TICK; TIME; LONG; LAT; HEIGHT; SPEED; UN; HDOP; SAT + //3801444, 080558, 2.944362, 43.262117, 295.28, 0.12964, 2, 2.900000, 3 + strftime(tbuffer, sizeof(tbuffer), "%H%M%S", gmtime(&wpt->creation_time)); + if (wpt->fix!=fix_unknown) { + switch (wpt->fix) + { + case fix_none: fix = 0; break; + case fix_2d: fix = 2; break; + default: fix = 0; break; + } + } + gbfprintf(fout, "%lu, %s, %lf, %lf, %5.1lf, %8.5lf, %d, %lf, %d\n", (unsigned long) wpt->creation_time,tbuffer, wpt->longitude, wpt->latitude,wpt->altitude, + wpt->speed,fix,wpt->hdop,wpt->sat); +} + + +static void +gopal_wr_init(const char *fname) +{ + fout = gbfopen(fname, "w", MYNAME); +} + +static void +gopal_wr_deinit(void) +{ + gbfclose(fout); +} + +static void +gopal_write(void) +{ + //route_disp_all(gopal_route_hdr, gopal_route_tlr, gopal_write_waypt); + if (global_opts.objective == wptdata) + { + waypt_disp_all(gopal_write_waypt); + + } else + //if (global_opts.objective == rtedata) + { + route_disp_all(gopal_route_hdr, gopal_route_tlr, gopal_write_waypt); + } +} + +static void +gopal_exit(void) /* optional */ +{ +} + +/**************************************************************************/ + +// capabilities below means: we can only read and write waypoints +// + +ff_vecs_t gopal_vecs = { + ff_type_file, + { + ff_cap_read | ff_cap_write /* waypoints */, + ff_cap_none /* tracks */, + ff_cap_read | ff_cap_write /* routes */ + }, + gopal_rd_init, + gopal_wr_init, + gopal_rd_deinit, + gopal_wr_deinit, + gopal_read, + gopal_write, + gopal_exit, + gopal_args, + CET_CHARSET_ASCII, 0 /* ascii is the expected character set */ + /* not fixed, can be changed through command line parameter */ +}; +/**************************************************************************/ diff --git a/gpsbabel/testo b/gpsbabel/testo index d6013a393..95fa09029 100755 --- a/gpsbabel/testo +++ b/gpsbabel/testo @@ -1351,4 +1351,23 @@ ${PNAME} -i gpx -f ${TMPDIR}/igo.gpx -o igo8 -F ${TMPDIR}/new-igo.trk ${PNAME} -i igo8 -f ${TMPDIR}/new-igo.trk -o gpx -F ${TMPDIR}/new-igo2.gpx compare ${TMPDIR}/igo.gpx ${TMPDIR}/new-igo2.gpx + +# GoPal +# GoPal is a bit tricky, because it's a lossy format regarding the first field (timetick). +# so we first read a reference gopal file, and then write it out as gopal trk file, now with a computed timestamp. +# Doing so results in more useful timestamps. +# Next we convert this tst file to gpx to test the writing path, but gpx does not save speed, so do it twice... +GoPalName=track20080703_173036.trk +rm -f ${TMPDIR}/${GoPalName}.* +#step 1: reference file +${PNAME} -i gopal -f ${REFERENCE}/track20080703_173036.trk -o gopal -F ${TMPDIR}/${GoPalName}.tst +#step2: gpx without speed information +${PNAME} -i gopal -f ${TMPDIR}/${GoPalName}.tst -o gpx -F ${TMPDIR}/${GoPalName}.im +${PNAME} -i gpx -f ${TMPDIR}/${GoPalName}.im -o gopal -F ${TMPDIR}/${GoPalName}.tst2 +#step 3: do it again to have 2 identical gopal files: +${PNAME} -i gopal -f ${TMPDIR}/${GoPalName}.tst -o gpx -F ${TMPDIR}/${GoPalName}.im2 +${PNAME} -i gpx -f ${TMPDIR}/${GoPalName}.im2 -o gopal -F ${TMPDIR}/${GoPalName}.tst3 +compare ${TMPDIR}/${GoPalName}.tst2 ${TMPDIR}/${GoPalName}.tst3 + + exit 0 diff --git a/gpsbabel/vecs.c b/gpsbabel/vecs.c index 4f6dba0e5..86b5006ad 100644 --- a/gpsbabel/vecs.c +++ b/gpsbabel/vecs.c @@ -140,6 +140,7 @@ extern ff_vecs_t destinator_trl_vecs; extern ff_vecs_t destinator_itn_vecs; extern ff_vecs_t exif_vecs; extern ff_vecs_t vidaone_vecs; +extern ff_vecs_t gopal_vecs; static vecs_t vec_list[] = { @@ -795,6 +796,12 @@ vecs_t vec_list[] = { "IGO8 .trk", "trk" }, + { + &gopal_vecs, + "gopal", + "GoPal GPS track log (.trk)", + "trk" + }, #endif // MAXIMAL_ENABLED { NULL, diff --git a/gpsbabel/xmldoc/formats/gopal.xml b/gpsbabel/xmldoc/formats/gopal.xml new file mode 100644 index 000000000..41c0fcbda --- /dev/null +++ b/gpsbabel/xmldoc/formats/gopal.xml @@ -0,0 +1,39 @@ +The gopal format is a track format written by the + + GoPal Navigation program. + + + The format of the file itself is quite simple: + + + Fileformat GoPal + TICK; TIME UTC; LONG; LAT; HEIGHT; SPEED km/h; FIX; HDOP; SAT + 3801444, 080558, 2.944362, 43.262117, 295.28, 0.12964, 2, 2.900000, 3 + + +Filenames are automatically created by the device as follows: + + trackYYYYMMDD_HHMMSS.trk + and/or, depending on software version and settings: + + A_YYYYMMDD_HHMMSS.trk + + with HHMMSS local time (not UTC!) + + +The file format lacks the correct date value for each trackpoint, so it has to be computed starting from the +date given in the filename. To handle files without a parsable date in the +name, the command line option 'date' is provided. + + +Conversions from gopal into any other format are a bit lossy concerning the first field of each line wich looks like an useless time tick value +and is simply discarded while reading. If written, there will be a time_t value from the current (computed) timestamp. + + + +Filtering out invalid data points is handled by the options 'clean', 'minspeed' and 'maxspeed'. +For each datapoint the speed needed to come the from the last valid point is +calculated and compared with the limits. +Thus one cat easily discard unreliable points. + + diff --git a/gpsbabel/xmldoc/formats/options/gopal-clean.xml b/gpsbabel/xmldoc/formats/options/gopal-clean.xml new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/gpsbabel/xmldoc/formats/options/gopal-clean.xml @@ -0,0 +1 @@ + diff --git a/gpsbabel/xmldoc/formats/options/gopal-date.xml b/gpsbabel/xmldoc/formats/options/gopal-date.xml new file mode 100644 index 000000000..e3c6abdea --- /dev/null +++ b/gpsbabel/xmldoc/formats/options/gopal-date.xml @@ -0,0 +1,3 @@ + + This option is useful if you have tracks from Gopal that have been renamed. + diff --git a/gpsbabel/xmldoc/formats/options/gopal-maxspeed.xml b/gpsbabel/xmldoc/formats/options/gopal-maxspeed.xml new file mode 100644 index 000000000..06122fce4 --- /dev/null +++ b/gpsbabel/xmldoc/formats/options/gopal-maxspeed.xml @@ -0,0 +1,3 @@ + + This is useful for removing wildly erroneous data from your recorded track. + diff --git a/gpsbabel/xmldoc/formats/options/gopal-minspeed.xml b/gpsbabel/xmldoc/formats/options/gopal-minspeed.xml new file mode 100644 index 000000000..13cf02035 --- /dev/null +++ b/gpsbabel/xmldoc/formats/options/gopal-minspeed.xml @@ -0,0 +1,3 @@ + + If this is greater than zero, duplicate waypoints will be removed. + -- 2.30.2